package org.speed.jdk;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


public class RingBufferDemo {
	
	private ScheduledExecutorService schedule = null;
	
	private ExecutorService pools = null;
	
	private Entry[] ringbuffer = new Entry[] {
			new Entry(),new Entry(),new Entry(),new Entry(),new Entry(),
			new Entry(),new Entry(),new Entry(),new Entry(),new Entry(),
			new Entry(),new Entry(),new Entry(),new Entry(),new Entry(),
			new Entry(),new Entry(),new Entry(),new Entry(),new Entry()
	};
	
	private int runIndex = 0;
	
	private int runCycle = 0;
	
	private AtomicInteger atomicInteger = new AtomicInteger(0);

	private Queue<Job> queue = new ArrayBlockingQueue<RingBufferDemo.Job>(1000);
	
	public void start() {
		schedule = Executors.newScheduledThreadPool(10);
		pools = Executors.newSingleThreadExecutor();
		
		schedule.scheduleAtFixedRate(new Runnable() {
			
				@Override
				public void run() {
					try {
						System.out.println("runCycle=" + runCycle + ",runIndex=" + runIndex + ",seq=" + atomicInteger.get());
						int seq = atomicInteger.incrementAndGet();
						
						List<Job> jobs = ringbuffer[runIndex].getJobs();
						moveNeedWillRunDelayJob(jobs,runIndex,runCycle);
						
						if(runIndex == ringbuffer.length - 1 ) {
							runIndex = 0;
						}else {
							runIndex ++;
						}
						
						runCycle = seq / ringbuffer.length ;
					}catch (Exception e) {
						e.printStackTrace();
					}
					
				}

				private void moveNeedWillRunDelayJob(List<Job> jobs, int runIndex, int runCycle) {
					Iterator<Job> iterator = jobs.iterator();
					while(iterator.hasNext()) {
						Job job = iterator.next();
						if(job.cycleNum == runCycle && job.index == runIndex) {
							queue.add(job);
							iterator.remove();
						}
					}
					
				}
				
		}, 0, 1, TimeUnit.SECONDS);
		
		pools.execute(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
					Job job = queue.poll();
					if(job != null) {
						job.run();
					}
				}
				
				
			}
		});
	}
	
	public void addJob(Job job) {
		
		int index = job.getDelayTime() % ringbuffer.length;
		int cycleNum = job.getDelayTime() / ringbuffer.length;
	
		job.setIndex(index);
		job.setCycleNum(cycleNum);
		
		if(ringbuffer[index] == null ) {
			ringbuffer[index] = new Entry();
		}
		ringbuffer[index].getJobs().add(job);
	}
	
	
	public static void main(String[] args) {
		RingBufferDemo ringBufferDemo = new RingBufferDemo();
		ringBufferDemo.start();
		
		ringBufferDemo.addJob(new Job(5, "5s"));
		ringBufferDemo.addJob(new Job(6, "6s"));
		ringBufferDemo.addJob(new Job(23, "23s"));
		ringBufferDemo.addJob(new Job(19, "19s"));
		
		ringBufferDemo.addJob(new Job(31, "31s"));
		
		ringBufferDemo.addJob(new Job(45, "45s"));
		ringBufferDemo.addJob(new Job(28, "28s"));
		ringBufferDemo.addJob(new Job(123, "123s"));
		ringBufferDemo.addJob(new Job(142, "142s"));

		
		
		
	}
	
	
	static class Entry {
		
		List<Job> jobs = new ArrayList();
		
		public List<Job> getJobs() {
			return jobs;
		}
		
	}
	
	static class Job implements Runnable {
		
		private int delayTime;
		
		private int cycleNum;
		
		private int index;
		
		private String name;
		
		

		public Job(int delayTime, String name) {
			this.delayTime = delayTime;
			this.name = name;
		}


		public int getCycleNum() {
			return cycleNum;
		}



		public void setCycleNum(int cycleNum) {
			this.cycleNum = cycleNum;
		}



		public int getIndex() {
			return index;
		}



		public void setIndex(int index) {
			this.index = index;
		}



		public int getDelayTime() {
			return delayTime;
		}


		public void setDelayTime(int delayTime) {
			this.delayTime = delayTime;
		}


		@Override
		public void run() {
			
			System.out.println(name + " run...");
			
		}
		
		
	}
	
	

}
